
#include <cmath>
#include <sstream>
#include <algorithm>

#include "Vector4.h"

using namespace Iride;

Vector4::Vector4(): x(0.0f), y(0.0f), z(0.0f), w(0.0f)
{
};

Vector4::Vector4(Real value): x(value), y(value), z(value), w(value)
{
};

Vector4::Vector4(const Vector3 &vec): x(vec.x), y(vec.y), z(vec.z), w(1.0)
{
};

Vector4::Vector4(Real fx, Real fy, Real fz, Real fw): x(fx), y(fy), z(fz), w(fw)
{
};

void Vector4::Swap(Vector4 &rOther)
{
	std::swap(x, rOther.x);
	std::swap(y, rOther.y);
	std::swap(z, rOther.z);
	std::swap(w, rOther.w);
}

Vector4 & Vector4::operator= (const Vector3 & other)
{
	x = other.x;
	y = other.y;
	z = other.z;
	w = 1.0;

	return *this;
}

Real Vector4::operator[] (const size_t index) const
{
	return *(&x + index);
}

Real& Vector4::operator[] (const size_t index)
{
	return *(&x + index);
}

Vector4 Vector4::operator- (void) const
{
	Vector4 result;
	result.x = - x;
	result.y = - y;
	result.z = - z;
	result.w = - w;

	return result;
}

Vector4 Vector4::operator+ (const Vector4& vec) const
{
	Vector4 result;
	result.x = x + vec.x;
	result.y = y + vec.y;
	result.z = z + vec.z;
	result.w = w + vec.w;

	return result;
}

Vector4 Vector4::operator- (const Vector4& vec) const
{
	Vector4 result;
	result.x = x - vec.x;
	result.y = y - vec.y;
	result.z = z - vec.z;
	result.w = w - vec.w;

	return result;
}

Vector4 Vector4::operator* (const Real& coeff) const
{
	Vector4 result;
	result.x = coeff*x;
	result.y = coeff*y;
	result.z = coeff*z;
	result.w = coeff*w;

	return result;
}

Vector4 Vector4::operator/ (const Real& coeff) const
{
	Vector4 result;
	result.x = x/coeff;
	result.y = y/coeff;
	result.z = z/coeff;
	result.w = w/coeff;

	return result;
}

Vector4& Vector4::operator+= (const Vector4& vec)
{
  *this = *this + vec;
  return *this;
}

Vector4& Vector4::operator-= (const Vector4& vec)
{
  *this = *this - vec;
  return *this;
}

Vector4 Vector4::Cross (const Vector4& vec) const
{
	Vector4 result;
	result.x = y * vec.z - z * vec.y;
	result.y = z * vec.x - x * vec.z;
	result.z = x * vec.y - y * vec.x;
	result.w = w * vec.w;

	return result;
}

Real Vector4::Length() const
{
	return sqrt(x*x + y*y + z*z);
}

bool Vector4::Normalize()
{
	Real Den = 1.0;

	Den = x*x + y*y + z*z;

	Den = sqrt(Den);

	if (Den != 0.0)
	{
		x=x/Den;
		y=y/Den;
		z=z/Den;

		return true;
	}
	else
	{
		return false;
	}
}

Vector3 Vector4::ToVector3()
{
	return Vector3(x,y,z);
}

Vector4 Vector4::Lerp (Vector4 vecA, Vector4 vecB, Real coeff )
{
	return vecA * coeff + vecB * (1.0 - coeff);
}

std::string Vector4::ToString() const
{
	std::stringstream out;
	out << x << " " << y << " " << z << " " << w << std::endl;
	return out.str();
}

const Vector4 Vector4::Zero = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
